﻿using System;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Text;
using OZDoo.Core.Exceptions;

namespace OZDoo.Core
{
    public sealed class DataProviders
    {
        /// <summary>
        /// This class can not be instantiated
        /// </summary>
        private DataProviders()
        {
        }

        private static void GetDataStoreParameters(Provider dataProvider, out string connectionString, out string databaseOwner)
        {
            databaseOwner = dataProvider.Attributes["databaseOwner"];
            if (databaseOwner == null || databaseOwner.Trim().Length == 0)
                databaseOwner = ConfigurationSettings.AppSettings[dataProvider.Attributes["databaseOwnerStringName"]];

            connectionString = dataProvider.Attributes["connectionString"];
            if (connectionString == null || connectionString.Trim().Length == 0)
                connectionString = ConfigurationSettings.AppSettings[dataProvider.Attributes["connectionStringName"]];
        }

        /// <summary>
        /// Creates an instance of the provider using Activator. This instance should be
        /// cached since it is an expesivie operation
        /// </summary>
        public static object CreateInstance(Provider dataProvider)
        {
            //Find the current attributes
            string connectionString = null; //dataProvider.Attributes["connectionString"];
            string databaseOwner = null;// dataProvider.Attributes["databaseOwner"];

            GetDataStoreParameters(dataProvider, out connectionString, out databaseOwner);

            //Get the type
            Type type = Type.GetType(dataProvider.Type);

            object newObject = null;
            if (type != null)
            {
                newObject = Activator.CreateInstance(type, new object[] { databaseOwner, connectionString });
            }

            if (newObject == null) //If we can not create an instance, throw an exception
               throw new ProviderException(dataProvider.Name);

            return newObject;
        }

        /// <summary>
        /// Creates and Caches the ConstructorInfo for the specified provider. 
        /// </summary>
        public static ConstructorInfo CreateConstructorInfo(Provider dataProvider)
        {

            // The assembly should be in \bin or GAC, so we simply need
            // to get an instance of the type
            //
            OzdConfiguration config = OzdConfiguration.GetConfig();
            ConstructorInfo providerCnstr = null;
            try
            {
                //string providerTypeName = ((Provider) config.Providers[providerName]).Type;
                Type type = Type.GetType(dataProvider.Type);

                // Insert the type into the cache
                //
                Type[] paramTypes = new Type[2];
                paramTypes[0] = typeof(string);
                paramTypes[1] = typeof(string);

                providerCnstr = type.GetConstructor(paramTypes);

            }
            catch
            {
                throw new ProviderException(dataProvider.Name);
            }

            if (providerCnstr == null)
                throw new ProviderException(dataProvider.Name);

            return providerCnstr;
        }

        /// <summary>
        /// Creates an instance of the specified provider using the Cached
        /// ConstructorInfo from CreateConstructorInfo
        /// </summary>
        public static object Invoke(Provider dataProvider)
        {
            object[] paramArray = new object[2];


            string dbOwner = null;
            string connstring = null;

            GetDataStoreParameters(dataProvider, out connstring, out dbOwner);

            paramArray[0] = dbOwner;
            paramArray[1] = connstring;

            return CreateConstructorInfo(dataProvider).Invoke(paramArray);
        }

    }
}
